﻿using System;
using OverStore.Runtime.PersistenceServiceProvider;
using System.Globalization;

namespace OverStore.Runtime.ObjectRepository.ChangesTracker
{
    /// <summary>
    /// Changes tracker that uses specified delegate to obtain object state that can be compared for define were object data changed since last changes accepting.
    /// </summary>
    /// <typeparam name="TInstance">The type of the instance.</typeparam>
    /// <typeparam name="TIdentifier">The type of the identifier.</typeparam>
    /// <typeparam name="TState">The type of the state.</typeparam>
    public sealed class DelegateChangesTracker<TInstance, TIdentifier, TState> : ChangesTrackerBase<TInstance, TIdentifier, TState>
        where TInstance : class
        where TState : IEquatable<TState>
    {
        private readonly Func<TInstance, TState> _GetState;

        /// <summary>
        /// Initializes a new instance of the <see cref="DelegateChangesTracker{TInstance, TIdentifier, TState}"/> class.
        /// </summary>
        /// <param name="provider">Object provides access to different services that allows to perform different task regarding persisting instance of specified type.</param>
        /// <param name="getState">Delegate allows to obtain object state.</param>
        public DelegateChangesTracker(IPersistenceServiceProvider provider, Func<TInstance, TState> getState)
            : base(provider)
        {
            if (Object.ReferenceEquals(getState, null))
                throw new ArgumentNullException("getState");
            _GetState = getState;
        }

        /// <summary>
        /// When overrided in derived classes, returns object state of specified instance.
        /// </summary>
        /// <param name="instance">Instance wich state should be got.</param>
        /// <returns>
        /// Object represents state of <paramref name="instance"/>.
        /// </returns>
        protected override TState GetObjectStateCore(TInstance instance)
        {
            try
            {
                return _GetState(instance);
            }
            catch (Exception ex)
            {
                throw new PersistingRuntimeException(
                    String.Format(
                        CultureInfo.InvariantCulture,
                        "Changes Tracker error: getting changes state of instance of type {0} failed.", 
                        typeof(TInstance)),
                    ex);
            }
        }
    }
}
